package gu.sql2java.json;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.BitSet;

import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.IntegerCodec;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.LongCodec;
import com.alibaba.fastjson.serializer.ObjectArrayCodec;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.PrimitiveArraySerializer;
import com.alibaba.fastjson.serializer.SerializeWriter;

/**
 * {@link BitSet} 的FASTJSON序列化和反序列化实现
 * @author guyadong
 * @since 3.30.1
 */
public class BitSetFastjsonCodec implements ObjectSerializer, ObjectDeserializer{
	public static final BitSetFastjsonCodec INSTANCE = new BitSetFastjsonCodec();
	private BitSetSerializeType bitSetSerializeType = BitSetSerializeType.ARRAY;
	final ObjectArrayCodec longArrayCodec = new ObjectArrayCodec();
	/** 最大bit位限制,大于等于此值的索引位值在序列化和反序列化时被忽略 */
	private Integer bitLimit;
    public BitSetFastjsonCodec() {
	}

	public BitSetFastjsonCodec(BitSetSerializeType bitSetSerializeType) {
		this.bitSetSerializeType(bitSetSerializeType);
	}

	public BitSetFastjsonCodec(Integer bitLimit) {
		if(null != bitLimit && bitLimit < 0) {
			throw new IllegalArgumentException("bitLimit < 0: " + bitLimit);
		}
		this.bitLimit = bitLimit;
	}

	/**
	 * 将索引大于等于length的位清0
	 * @param bitSet
	 * @param length
	 * @return 输入参数为{@code null}返回原值，否则返回清0后的新对象
	 */
	public static BitSet leftSet(BitSet bitSet,Integer length) {
		if(null != bitSet && null != length) {
			if(length < bitSet.length()) {
				return bitSet.get(0,length);
			}
		}
		return bitSet;
	}
	@SuppressWarnings({ "unchecked" })
	@Override
	public <T>T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        JSONLexer lexer = parser.lexer;
        switch(lexer.token()) {
        case JSONToken.NULL:
        	 lexer.nextToken(JSONToken.COMMA);
             return null;
        case JSONToken.LITERAL_STRING:{
        	/** 递归 */
        	String stringLiteral = lexer.stringVal();
        	DefaultJSONParser _parser = new DefaultJSONParser(stringLiteral, parser.getConfig());
        	BitSet bitSet =  deserialze(_parser, type, fieldName);
        	lexer.nextToken(JSONToken.COMMA);
        	return (T) bitSet;
        }
        case  JSONToken.HEX:{
            byte[] bytes = lexer.bytesValue();
            lexer.nextToken(JSONToken.COMMA);
            return (T) leftSet(BitSet.valueOf(bytes), bitLimit);
        }        	
        case  JSONToken.LBRACKET:{
			long[] longs = longArrayCodec.deserialze(parser, long[].class, fieldName);
			return (T) leftSet(BitSet.valueOf(longs), bitLimit);
		}
        case JSONToken.LBRACE:{
			lexer.nextToken();
			BitSet bitSet = new BitSet();
			while(lexer.token() != JSONToken.RBRACE) {
				if (lexer.token() == JSONToken.COMMA) {
                    lexer.nextToken();
                    continue;
                }
				Integer bitIndex = IntegerCodec.instance.deserialze(parser, Integer.class, fieldName);
				if(null != bitIndex) {
					bitSet.set(bitIndex);
				}
			}
			lexer.nextToken(JSONToken.COMMA);
			return (T) leftSet(bitSet, bitLimit);
		}
        default: {
			Long value = LongCodec.instance.deserialze(parser, Long.class, fieldName);
			return (T) leftSet(BitSet.valueOf(new long[] {value}), bitLimit);
		}
        }
	}

	@Override
	public int getFastMatchToken() {
		return JSONToken.LBRACKET;
	}

	@Override
	public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)
			throws IOException {
		 if (null==object || ! (object instanceof BitSet)) {
			 serializer.writeNull();
			 return;
		 }
		 SerializeWriter out = serializer.out;
		 BitSet bitSet = (BitSet)object;
		 if(null != bitLimit) {
			 bitSet = leftSet(bitSet, bitLimit);
			 if(bitLimit <= Long.SIZE) {
				 out.writeLong(bitSet.toLongArray()[0]);
				 return;
			 }
		 }
		 switch(bitSetSerializeType) {
		 case ARRAY:
			 PrimitiveArraySerializer.instance.write(serializer, bitSet.toLongArray(), fieldName, fieldType, features);
			 break;
		 case TO_STRING:
	        out.write(bitSet.toString());
			 break;
		 case HEX:
			 out.writeHex(bitSet.toByteArray());
			 break;
		 default:
			 throw new UnsupportedOperationException();
		 }
	}

	public BitSetFastjsonCodec bitSetSerializeType(BitSetSerializeType bitSetSerializeType) {
		if(null != bitSetSerializeType) {
			this.bitSetSerializeType = bitSetSerializeType;
		}
		return this;
	}
	public static class I8 extends BitSetFastjsonCodec{
		public I8() {
			super(Byte.SIZE);
		}
	}
	public static class I16 extends BitSetFastjsonCodec{
		public I16() {
			super(Short.SIZE);
		}
	}
	public static class I32 extends BitSetFastjsonCodec{
		public I32() {
			super(Integer.SIZE);
		}
	}
	public static class I64 extends BitSetFastjsonCodec{
		public I64() {
			super(Long.SIZE);
		}
	}
	/**
	 * {@link BitSet}序列化字符类型
	 * @author guyadong
	 *
	 */
	public enum BitSetSerializeType{
		/** []整数数组 */ARRAY,
		/** {}包含的整数序列 */TO_STRING,
		/** 十六进制字符串 */HEX
	}
}
